# Leer página
url <- "https://www.billboard.com/charts/hot-100/"
pagina <- read_html(url)
# Selector correcto en octubre 2025
filas <- pagina |> html_elements(".o-chart-results-list-row")
# Si no hay filas, usar fallback
if (length(filas) == 0) {
filas <- pagina |> html_elements(xpath = "//li[.//h3[contains(@class, 'c-title')]]")
cat("Fallback: filas detectadas:", length(filas), "\n")
}
extraer_fila <- function(fila) {
spans <- fila |> html_elements("span.c-label")
if (length(spans) < 1) {
return(tibble(posicion = NA, titulo = NA, artista = NA, semanas_en_lista = NA, cambio_posicion = NA))
}
# Posición
posicion <- as.numeric(spans[[1]] |> html_text2() |> str_squish())
# Título completo (contiene también el artista a veces)
h3_text <- fila |> html_element("h3.c-title") |> html_text2() |> str_squish()
# Todos los labels visibles
labels_raw <- spans |> html_text2() |> str_squish()
labels <- labels_raw[str_detect(labels_raw, "\\S")]
# Filtramos etiquetas especiales
labels_filtrados <- labels[!labels %in% c("NEW", "--")]
# Artista inicial
artista <- if (length(labels_filtrados) >= 2) labels_filtrados[2] else NA
# Normalizamos texto del artista
artista_norm <- artista %>%
str_to_lower() %>%
str_replace_all("\\s", "") %>%
str_replace_all("[^a-z0-9\\-]", "")
# Si detecta RE-ENTRY en el campo del artista
if (!is.na(artista) && grepl("^re-?entry$", artista_norm)) {
# Intentar buscar el nombre del artista en el siguiente div hermano
nuevo_artista <- tryCatch({
siguiente_nodo <- fila |> html_element(xpath = "following-sibling::div[1]")
if (!is.null(siguiente_nodo)) {
siguiente_nodo |> html_element("span.c-label") |> html_text2() |> str_squish()
} else {
NA
}
}, error = function(e) NA)
# Si lo encuentra, reemplaza
if (!is.na(nuevo_artista) && nzchar(nuevo_artista)) {
artista <- nuevo_artista
} else {
artista <- NA
}
}
# Semanas en lista: último número detectable
wks_on_chart <- suppressWarnings(as.numeric(tail(labels_filtrados, 1)))
# Última posición (para cambio) - buscamos número dentro de labels antes del último
last_week <- suppressWarnings(as.numeric(labels_filtrados[3]))
cambio <- if (!is.na(last_week) && !is.na(posicion)) last_week - posicion else NA
# Limpiar título eliminando el artista del final si aparece
titulo <- h3_text
if (!is.na(artista) && nzchar(artista)) {
patron <- paste0("\\s*", str_trim(artista), "$")
if (str_detect(h3_text, regex(patron, ignore_case = TRUE))) {
titulo <- str_remove(h3_text, regex(patron, ignore_case = TRUE))
}
}
tibble(
posicion = posicion,
titulo = str_squish(titulo),
artista = str_squish(artista),
semanas_en_lista = wks_on_chart,
cambio_posicion = cambio
)
}
datos_billboard <- filas |> map_dfr(extraer_fila, .id = NULL)
# Aplicar y limpiar
datos_billboard <- filas |>
map_dfr(extraer_fila) |>
filter(!is.na(posicion), !is.na(titulo), titulo != "", !is.na(artista), artista != "") |>
arrange(posicion) |>
mutate(
tipo_artista = case_when(
str_detect(artista, regex("featuring|feat\\.|&|,|/|:", ignore_case = TRUE)) ~ "colaboración",
TRUE ~ "artista"
),
origen = "billboard"
)
DT::datatable(datos_billboard,
options = list(pageLength = 15, autoWidth = TRUE),
caption = 'Billboard 100 Ranking'
)Tarea 2. Web scraping aplicado
Datos no Estructurados
Introducción
Esta práctica aplica técnicas de web scraping estático y dinámico para analizar las dinámicas actuales del mercado musical, comparando el éxito en Estados Unidos (Billboard Hot 100) con el éxito global en Apple Music. El objetivo es demostrar capacidad para extraer, limpiar, enriquecer e interpretar datos web con valor analítico en el ámbito de la industria musical, el marketing digital y los estudios culturales.
Se han seleccionado fuentes no usadas en clase, cumpliendo con la prohibición del enunciado, y se han implementado:
- Parte A: Scraping estático de Billboard Hot 100 con
rvest. - Parte B: Scraping dinámico de Kworb.net (Apple Music Global) con
RSelenium, con ≥3 interacciones reales. - Enriquecimiento: extracción de metadatos de álbum desde Genius.com.
Parte A: Scraping estático – Billboard Hot 100
El propósito de esta sección es extraer y estructurar información del ranking musical Billboard Hot 100, uno de los indicadores más influyentes en la industria musical estadounidense y mundial. El objetivo principal es recopilar de forma automatizada los siguientes datos correspondientes a la semana actual:
- Posición
- Título de la canción
- Artista
- Semanas en lista
- Cambio de posición respecto a la semana anterior
Análisis del HTML y decisión de selectores
Tras inspeccionar la página https://www.billboard.com/charts/hot-100/ mediante las herramientas de desarrollo del navegador, se identificó lo siguiente:
Cada entrada del ranking se encuentra dentro de un bloque estructural repetido.
La posición aparece como texto al inicio de cada bloque.
El título y el artista están concatenados dentro de un elemento
<h3 class=c-title>Las métricas adicionales (semanas en lista, posición anterior, posición máxima) aparecen como números en etiquetas
<span class=c-label>, pero sin identificadores semánticos claros.En los casos de canciones nuevas (“NEW”) o reentradas (“RE-ENTRY”), estas etiquetas alteran el orden habitual de las métricas.
A partir de estas observaciones, se tomaron las siguientes decisiones metodológicas:
Seleccionar cada bloque de canción con html_elements(“.o-chart-results-list-row”).
Extraer todas las etiquetas
<span class=c-label>y filtrar manualmente las etiquetas “NEW”, “RE-ENTRY” y “–”.Calcular el cambio de posición como la diferencia entre la posición anterior (last_week) y la posición actual (posicion_actual).
El scraping permite responder preguntas clave:
- ¿Qué canciones tienen longevidad (>50 semanas)? Ej: “Lose Control” de Teddy Swims (102 semanas).
- ¿Qué artistas dominan con colaboraciones? Ej: Morgan Wallen con múltiples features.
- ¿Hay éxitos efímeros (1–2 semanas) vs. éxitos sostenidos?
Este tipo de análisis es de gran valor para:
- Industria musical: planificación de lanzamientos.
- Marketing digital: estrategias de promoción en redes.
- Estudios culturales: comprensión de tendencias sociales.
Parte B – Scraping dinámico: Apple Music Global Chart (vía Kworb.net)
El propósito de esta segunda parte es realizar un proceso de scraping dinámico utilizando RSelenium para automatizar la extracción de datos de una página web que requiere interacción con el navegador.
En este caso, se ha seleccionado la página Kworb.net – Apple Music Global Chart, una fuente no tratada en clase que recopila, en tiempo real, las canciones más escuchadas a nivel mundial en la plataforma Apple Music.
La elección de este sitio responde a su relevancia analítica y a su nivel de dificultad técnica:
- Es una web que requiere interacción mediante scroll para cargar progresivamente la totalidad de la tabla.
- Posee un aviso de cookies que bloquea la navegación hasta su aceptación.
- Contiene una tabla dinámica que solo se carga de forma completa tras varias acciones automáticas.
Al inspeccionar la estructura HTML de Kworb.net se observa que: - La tabla principal de resultados está contenida dentro de un único elemento <table>, que se genera dinámicamente tras el scroll. - Los datos de posición, artista, canción, streams y variación se encuentran dentro de celdas <td>. - No existen etiquetas semánticas diferenciadas (por ejemplo, no hay atributos id o class únicos para cada columna), por lo que es necesario extraer el contenido de las celdas por posición.
Para acceder y extraer los datos correctamente hemos hecho lo siguiente:
- Aceptar cookies → mediante la búsqueda del botón
button.fc-button.fc-cta-consent.fc-primary-button.
- Scroll hasta el final de la página → para forzar la carga completa de la tabla (
executeScript("window.scrollTo(0, document.body.scrollHeight);")).
3. Extracción del contenido tabular dinámico → una vez cargado, se identifican las filas (
<tr>) y celdas (<td>) del HTML para crear un dataframe limpio.
Cada interacción está documentada con su selector CSS correspondiente, y se han incorporado pausas (Sys.sleep()) y funciones auxiliares (find_or_null, wait_brief) para garantizar la estabilidad del proceso.
# ---- Arranque Firefox ----
rD <- rsDriver(browser = "firefox",
geckover = "latest",
iedrver = NULL,
chromever = NULL,
phantomver = NULL)[1] "Connecting to remote server"
$acceptInsecureCerts
[1] FALSE
$browserName
[1] "firefox"
$browserVersion
[1] "144.0.2"
$`moz:accessibilityChecks`
[1] FALSE
$`moz:buildID`
[1] "20251027123126"
$`moz:geckodriverVersion`
[1] "0.36.0"
$`moz:headless`
[1] FALSE
$`moz:platformVersion`
[1] "10.0"
$`moz:processID`
[1] 15304
$`moz:profile`
[1] "C:\\Users\\ymari\\AppData\\Local\\Temp\\rust_mozprofilepjIvKc"
$`moz:shutdownTimeout`
[1] 60000
$`moz:webdriverClick`
[1] TRUE
$`moz:windowless`
[1] FALSE
$pageLoadStrategy
[1] "normal"
$platformName
[1] "windows"
$proxy
named list()
$setWindowRect
[1] TRUE
$strictFileInteractability
[1] FALSE
$timeouts
$timeouts$implicit
[1] 0
$timeouts$pageLoad
[1] 300000
$timeouts$script
[1] 30000
$unhandledPromptBehavior
[1] "dismiss and notify"
$userAgent
[1] "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:144.0) Gecko/20100101 Firefox/144.0"
$webdriver.remote.sessionid
[1] "a2bf42a8-3a80-47a5-94e4-4e5164293434"
$id
[1] "a2bf42a8-3a80-47a5-94e4-4e5164293434"
driver <- rD[["client"]]
# Entramos en la web
driver$navigate("https://kworb.net/apple_songs/")
Sys.sleep(3)
# ---- Interacción 1: aceptar cookies ----
element <- driver$findElement(using = "css selector",
"button.fc-button.fc-cta-consent.fc-primary-button")
element$clickElement()
Sys.sleep(1)
driver$setTimeout(type = "implicit", milliseconds = 10000)
# ---- Helpers ----
find_or_null <- function(css) {
tryCatch(driver$findElement(using = "css", value = css), error = function(e) NULL)
}
wait_brief <- function() Sys.sleep(1.5)
# ---- Interacción 2: Scroll hasta el final para cargar toda la tabla ----
message("Haciendo scroll para cargar datos...")
for (i in 1:8) {
driver$executeScript("window.scrollTo(0, document.body.scrollHeight);")
wait_brief()
}
# ---- Interacción 3: Verificar que la tabla esté presente antes de extraer ----
table_element <- find_or_null("table")
if (is.null(table_element)) {
stop("No se cargó la tabla de datos después del scroll.")
}
message("Tabla detectada. Procediendo a la extracción...")
# ---- Extraer datos de la tabla ----get_table_data <- function() {
get_table_data <- function() {
rows <- driver$findElements(using = "css", value = "table tr")
if (length(rows) <= 1) return(tibble(posicion = numeric(), artista = character(), cancion = character(), streams = numeric(), cambio = numeric()))
data_rows <- rows[-1] # eliminar encabezado
results <- lapply(data_rows, function(row) {
cells <- row$findChildElements(using = "css", value = "td")
if (length(cells) < 5) return(NULL)
# Posición
pos_txt <- cells[[1]]$getElementText()[[1]]
posicion <- as.numeric(gsub("[^0-9]", "", pos_txt))
# Artista y canción
artista <- cells[[2]]$getElementText()[[1]]
cancion <- cells[[3]]$getElementText()[[1]]
# Streams del último día
streams_txt <- cells[[4]]$getElementText()[[1]]
streams <- as.numeric(gsub("[^0-9]", "", streams_txt))
# Cambio de posición (manejar guión largo "–")
cambio_txt <- cells[[5]]$getElementText()[[1]]
cambio <- if (cambio_txt == "–") {
NA_real_
} else {
cambio_clean <- gsub("–", "-", cambio_txt) # guión largo → guión corto
as.numeric(cambio_clean)
}
tibble(
posicion = posicion,
p_mas = artista,
artista_cancion = cancion,
streams_ultimo_dia = streams,
cambio_global = cambio
)
})
bind_rows(results)
}
datos_apple <- get_table_data()
# Arreglamos el dataframe y nos quedamos con las 100 primeras canciones para simplificar el posterior análisis
datos_apple <- datos_apple %>%
separate(artista_cancion, into = c("artista", "titulo"), sep = " - ", extra = "merge", fill = "right") %>%
select(-p_mas) %>%
head(100)
# Añaidomos el origen de cada fuente y juntas los dos dataframes en uno solo de forma que hay columnas vacías debido a las distintas fuentes. No obstante, no resulta un inconveniente para nuestro análisis.
datos_billboard <- datos_billboard %>%
mutate(origen = "billboard")
datos_apple <- datos_apple %>%
mutate(origen = "apple")
df_combinado <- bind_rows(datos_billboard, datos_apple)A continuación accedemos a la página de Genius.com para complementar la información de canciones y artistas presentes en los charts de Billboard y Apple Music . El objetivo principal es automatizar la obtención de datos adicionales, como el álbum al que pertenecen y la fecha de publicación, usando RSelenium para interactuar con la web. Esto permite enriquecer nuestro conjunto de datos df_combinado con información que no está disponible directamente en los rankings de Billboard y Apple.
Bucle de búsqueda y extracción
Posteriormente, para cada canción en df_combinado, se realiza lo siguiente:
- Búsqueda de la canción mediante el input de búsqueda en Genius.com.
Selección del resultado correcto, comparando el nombre del artista registrado en nuestro dataframe con coincidencias flexibles (primeros 6 caracteres) para manejar pequeñas diferencias en los nombres.
Extracción de información:
Nombre del álbum al que pertenece la canción.
Fecha de publicación de la canción.
Se implementa un manejo de errores robusto (tryCatch) para asegurar que el bucle continúe aunque algún elemento no se encuentre.
for (i in 1:nrow(df_combinado)) {
titulo_actual <- df_combinado$titulo[i]
artista_actual <- df_combinado$artista[i]
# Evitar filas vacías o con NA
if (is.na(titulo_actual) || is.na(artista_actual) ||
titulo_actual == "" || artista_actual == "") {
# Se omite fila sin mostrar mensaje
next
}
tryCatch({
# Volver a la página principal
remDr$navigate("https://genius.com/")
Sys.sleep(2)
# Buscar el input
input_elem <- remDr$findElement(using = "css selector", 'input[name="q"]')
input_elem$clearElement()
Sys.sleep(0.5)
input_elem$sendKeysToElement(list(titulo_actual))
Sys.sleep(1)
# Click en el botón de búsqueda
tryCatch({
boton <- remDr$findElement(using = "css selector", ".StickyNavSearch-desktop__Icon-sc-5a06ff1a-1")
boton$clickElement()
}, error = function(e) {
# Fallback si cambia el selector
boton_alt <- remDr$findElement(using = "css selector", "button[class*='Search']")
boton_alt$clickElement()
})
Sys.sleep(2)
# Extraer las tarjetas de resultados
tarjetas <- remDr$findElements(using = "css selector", "div.u-quarter_vertical_margins.u-clickable")
artista_target <- tolower(trimws(artista_actual))
match_encontrado <- FALSE
for (tarjeta in tarjetas) {
tryCatch({
subtitulo <- tarjeta$findElement(using = "css selector", ".mini_card-subtitle")
texto_artista <- subtitulo$getElementText()[[1]]
partes <- unlist(strsplit(texto_artista, "\n"))
if (length(partes) >= 2) {
artista_extraido <- tolower(trimws(partes[2]))
# Coincidencia flexible entre nombres
if (stringr::str_detect(artista_extraido, stringr::str_sub(artista_target, 1, 4)) ||
stringr::str_detect(artista_target, stringr::str_sub(artista_extraido, 1, 4))) {
tarjeta$clickElement()
match_encontrado <- TRUE
break
}
}
}, error = function(e) {})
}
Sys.sleep(2)
# Obtener el álbum (si existe)
tryCatch({
album_elem <- remDr$findElement(using = "css selector", 'a[href*="primary-album"]')
album_name <- album_elem$getElementText()[[1]]
df_combinado$album[i] <- album_name
}, error = function(e) {
df_combinado$album[i] <- NA
})
# Obtener la fecha de publicación
tryCatch({
fecha_elem <- remDr$findElement(using = "xpath", "//span[contains(text(), 'Jan.') or contains(text(), 'Feb.') or contains(text(), 'Mar.') or contains(text(), 'Apr.') or contains(text(), 'May.') or contains(text(), 'Jun.') or contains(text(), 'Jul.') or contains(text(), 'Aug.') or contains(text(), 'Sep.') or contains(text(), 'Oct.') or contains(text(), 'Nov.') or contains(text(), 'Dec.')]")
fecha_text <- fecha_elem$getElementText()[[1]]
df_combinado$fecha_publicacion[i] <- fecha_text
}, error = function(e) {
df_combinado$fecha_publicacion[i] <- NA
})
}, error = function(e) {
cat(paste0("❌ Error en la fila ", i, ": ", e$message, "\n"))
})
Sys.sleep(2)
}Una vez ya tenemos nuestro dataframe completo realizamos el análisis comparativo final entre los rankings de Billboard (EE. UU.) y Apple Music (Global). El propósito es observar diferencias y similitudes en la popularidad de las canciones según la plataforma, identificando patrones relacionados con la posición en el ranking, la duración en las listas y la presencia de artistas o álbumes comunes en ambas plataformas.
df <- df_combinado |>
filter(!is.na(posicion)) |>
mutate(
# Agrupar por origen
origen = case_when(
origen == "billboard" ~ "Billboard (EE.UU.)",
origen == "apple" ~ "Apple Music (Global)",
TRUE ~ "Otro"
),
# Clasificar semanas en categorías
longevidad = case_when(
semanas_en_lista >= 50 ~ "Muy larga (≥50 semanas)",
semanas_en_lista >= 20 ~ "Larga (20–49 semanas)",
semanas_en_lista >= 5 ~ "Media (5–19 semanas)",
semanas_en_lista >= 1 ~ "Corta (<5 semanas)",
TRUE ~ "Desconocida"
),
# Normalizar artista para unir mejor
artista_norm = str_to_title(str_remove_all(artista, "[^a-zA-Z ]"))
)Análisis de estabilidad y tendencia
El siguiente gráfico compara la estabilidad de las canciones en el ranking de Billboard con la variación reciente del rendimiento global en Apple Music.
Para Billboard, se muestran cuántas canciones han permanecido varias semanas en el top.
En Apple Music, se observa la distribución del cambio global, indicando si las canciones están subiendo, bajando o manteniéndose estables.
df_stabilidad <- df_combinado %>%
mutate(
variable = ifelse(origen == "billboard", semanas_en_lista, cambio_global),
etiqueta = ifelse(origen == "billboard", "Semanas en lista (Billboard)", "Cambio global (Apple Music)")
) %>%
filter(!is.na(variable))
# Histograma Billboard
g_billboard <- df_stabilidad %>%
filter(origen == "billboard") %>%
ggplot(aes(x = variable)) +
geom_histogram(bins = 20, fill = "#E41A1C", color = "white", alpha = 0.85) +
labs(
title = "Estabilidad en Billboard",
subtitle = "Distribución de semanas en lista",
x = "Semanas en lista",
y = "Número de canciones"
) +
theme_economist() +
theme(
plot.title = element_text(face = "bold", size = 16, hjust = 0.5),
plot.subtitle = element_text(margin = margin(b = 15, t = 10), hjust = 0.5),
axis.title.x = element_text(margin = margin(t = 15)),
axis.title.y = element_text(margin = margin(r = 15))
)
# Histograma Apple Music
g_applemusic <- df_stabilidad %>%
filter(origen != "billboard") %>%
ggplot(aes(x = variable)) +
geom_histogram(bins = 20, fill = "#377EB8", color = "white", alpha = 0.85) +
labs(
title = "Tendencia en Apple Music",
subtitle = "Distribución del cambio global",
x = "Cambio global",
y = "Número de canciones"
) +
theme_economist() +
theme(
plot.title = element_text(face = "bold", size = 16, hjust = 0.5),
plot.subtitle = element_text(margin = margin(b = 15, t = 10), hjust = 0.5),
axis.title.x = element_text(margin = margin(t = 15)),
axis.title.y = element_text(margin = margin(r = 15))
)
# Boxplot comparativo
g_boxplot <- ggplot(df_stabilidad, aes(x = etiqueta, y = variable, fill = etiqueta)) +
geom_boxplot(alpha = 0.7, outlier.alpha = 0.4) +
scale_fill_manual(
values = c("Semanas en lista (Billboard)" = "#E41A1C", "Cambio global (Apple Music)" = "#377EB8"),
name = "Origen"
) +
labs(
title = "Comparativa de estabilidad y cambio",
x = NULL,
y = "Valor"
) +
theme_economist() +
theme(
plot.title = element_text(face = "bold", size = 16, hjust = 0.5),
plot.subtitle = element_text(margin = margin(b = 15, t = 10), hjust = 0.5),
axis.title.x = element_text(margin = margin(t = 15)),
axis.title.y = element_text(margin = margin(r = 15)),
legend.position = "bottom"
)El primer gráfico muestra la distribución de canciones según su permanencia en el Billboard Hot 100. Se observa una clara bimodalidad: por un lado, un grupo importante de canciones con menos de 5 semanas en lista, lo que refleja éxitos efímeros, posiblemente virales o impulsados por lanzamientos recientes. Por otro lado, un segundo grupo de canciones con más de 30 semanas en el ranking, como “Ordinary” de Alex Warren (38 semanas) o “Wildflower” de Billie Eilish (73 semanas), que demuestran una longevidad excepcional. Esto sugiere que el mercado musical actual no solo premia la novedad, sino también la resonancia sostenida a través del tiempo.
El segundo gráfico representa la distribución del cambio de posición en Apple Music Global. La mayoría de las canciones muestran un cambio cercano a cero, lo que indica estabilidad en el ranking global. Sin embargo, se aprecian algunos picos tanto de subidas fuertes (valores positivos altos) como de caídas abruptas (valores negativos altos). Estos movimientos extremos suelen corresponder a nuevos lanzamientos (como las nuevas canciones del álbum de Rosalía) o a canciones que pierden impulso tras semanas de promoción.
El boxplot comparativo evidencia la diferencia de comportamiento entre ambos rankings:
Billboard tiende a mostrar mayor estabilidad, con canciones manteniéndose varias semanas en el top.
Apple Music presenta una dispersión más amplia en el cambio global, indicativo de su dinámica diaria y la competencia intensa por la visibilidad internacional.
Esta diferencia subraya que, pese a la globalización del streaming, las dinámicas de consumo siguen estando fuertemente influenciadas por factores culturales y regionales, lo que tiene implicaciones directas para sellos discográficos, estrategias de marketing y análisis de tendencias musicales.
En conjunto, se puede concluir que el ranking de Billboard se caracteriza por premiar la permanencia y el éxito continuado de los hits, mientras que Apple Music refleja un consumo global más inmediato y sujeto a cambios diarios. Estos resultados permiten interpretar que la estabilidad de una canción puede ser más relevante en rankings tradicionales, mientras que la tendencia y la variabilidad son rasgos destacables en entornos digitales y globales.
Distribución de posiciones por plataforma
El gráfico siguiente muestra la distribución de frecuencia de las posiciones que ocupan las canciones en ambas plataformas, lo que permite comparar cómo se distribuye la popularidad en EE.UU. (Billboard) frente a la popularidad global (Apple Music).
g_posiciones <- df_combinado %>%
ggplot(aes(x = posicion, fill = origen)) +
geom_histogram(bins = 20, alpha = 0.7, position = "dodge", color = "white") +
scale_fill_manual(
values = c("billboard" = "#E41A1C", "apple" = "#377EB8"),
name = "Origen",
labels = c("billboard" = "Billboard (EE.UU.)", "apple" = "Apple Music (Global)")
) +
labs(
title = "Distribución de posiciones: Billboard vs. Apple Music",
x = "Posición en el ranking",
y = "Frecuencia",
fill = "Origen"
) +
theme_economist() +
theme(
plot.title = element_text(face = "bold", size = 16, hjust = 0.5, margin = margin(b = 10)),
axis.title.x = element_text(margin = margin(t = 15)),
axis.title.y = element_text(margin = margin(r = 15)),
legend.position = "bottom"
)
print(g_posiciones)Se observa que tanto en Billboard como en Apple Music, las canciones se distribuyen de forma bastante uniforme a lo largo del ranking, sin una evidente concentración masiva en los primeros puestos. Las frecuencias de aparición por rango de posiciones son similares, lo que sugiere que en ambos sistemas las canciones logran ocupar posiciones en distintos segmentos, desde el top hasta el final del ranking. Esto sugiere que ambas plataformas permiten un acceso más equitativo a los rankings, aunque con diferentes dinámicas:
En Billboard, la presencia de artistas como Taylor Swift, Morgan Wallen o Sabrina Carpenter en los primeros puestos refleja una estrategia de promoción muy enfocada al mercado estadounidense.
En Apple Music Global, la presencia de Rosalía, BLACKPINK o ROSÉ & Bruno Mars en el top 30 demuestra que el éxito global está impulsado por mercados asiáticos y europeos.
La similitud en la forma de las distribuciones (ambas con picos iniciales y luego caídas progresivas) sugiere que, a pesar de las diferencias culturales, el modelo de consumo musical sigue patrones universales: los primeros puestos son los más codiciados, pero la rotación es alta.
Este análisis resulta útil para:
Sellos discográficos: entender dónde enfocar sus campañas de lanzamiento.
Plataformas de streaming: optimizar algoritmos de recomendación.
Estudios de mercado: identificar tendencias regionales y globales.
Artistas con mayor presencia en ambas plataformas
Aquí se muestra qué artistas aparecen con mayor frecuencia, tanto en Billboard como en Apple Music, indicando quiénes dominan actualmente el panorama musical.
top_artistas <- df_combinado %>%
filter(!grepl("re[- ]*entry", tolower(artista))) %>%
group_by(origen, artista) %>%
summarise(titulos = n(), .groups = "drop") %>%
arrange(origen, desc(titulos)) %>%
group_by(origen) %>%
slice_max(order_by = titulos, n = 5, with_ties = FALSE) %>%
ungroup()
DT::datatable(
top_artistas,
options = list(pageLength = 10, autoWidth = TRUE),
caption = 'Top 5 artistas por plataforma'
)En Apple Music Global, Taylor Swift lidera con 12 canciones en el top, seguida por ROSALÍA (11) y Olivia Dean (5). Este resultado refleja un éxito global sostenido, especialmente en mercados como Europa y América Latina, donde el pop y el flamenco contemporáneo tienen gran aceptación. La presencia de Bad Bunny (4) y HUNTR/X (4) confirma que el reggaetón y el K-pop están ganando terreno a nivel mundial.
En Billboard Hot 100 (EE.UU.), Taylor Swift vuelve a liderar con 11 canciones, lo que demuestra su capacidad para mantenerse en la cima del mercado estadounidense. Le siguen HUNTR/X (4), Olivia Dean (4) y Sabrina Carpenter (4).
Estos datos permiten extraer varias conclusiones clave:
- Taylor Swift es la artista más presente en ambas plataformas, lo que indica una estrategia de lanzamiento excepcionalmente efectiva tanto en EE.UU. como a nivel global.
- El grupo HUNTR/X aparece en ambos rankings, lo que sugiere que sus colaboraciones tienen un impacto transversal y el gran impacto de la película Kpop Demons Hunters.
- Olivia Dean tiene una presencia significativa en ambas listas, lo que apunta a un estilo musical que resuena tanto en EE.UU. como en el mercado global.
Álbumes destacados
Por último, se identifican los álbumes con mayor cantidad de canciones en las listas, tanto de Billboard como de Apple Music.
top_albumes <- df_combinado %>%
filter(!is.na(album)) %>%
group_by(album) %>%
summarise(titulos = n(), .groups = "drop") %>%
arrange(desc(titulos)) %>%
# toma los 5 primeros índices por grupo
filter(row_number() <= 5) %>%
ungroup()
DT::datatable(
top_albumes,
options = list(pageLength = 5, autoWidth = TRUE),
caption = 'Top 5 álbumes'
)El álbum “The Life of a Showgirl” de Taylor Swift lidera con 10 canciones en el top 100, lo que refleja una estrategia de lanzamiento excepcionalmente efectiva: múltiples singles promocionados simultáneamente, cada uno con su propia campaña visual y viral.
En segundo lugar, el álbum “KPop Demon Hunters (Soundtrack from the Netflix Film / Deluxe Version)” aparece con 5 canciones, lo que indica que el K-pop está logrando un éxito masivo no solo con artistas individuales, sino también con proyectos colaborativos y proyectos cinematográficos.
Los álbumes “I’m The Problem” y “Man’s Best Friend (Bonus Track)” (ambos con 2 canciones) sugieren que estos proyectos tienen un enfoque más selectivo, pero con alto rendimiento en las listas.
Canciones nuevas vs. recurrentes
Además de identificar los artistas y álbumes más destacados, resulta interesante observar qué proporción de canciones son nuevas entradas frente a aquellas que ya estaban en el ranking en semanas anteriores.
En Billboard, esta información se obtiene directamente a partir de la variable semanas_en_lista.
En Apple Music, al no contar con semanas acumuladas, se infiere a partir del campo “cambio global”:
- Un valor muy alto (por ejemplo, ±0 o cercano a ±1) suele indicar una nueva entrada o una posición reciente.
- Los valores intermedios o negativos sugieren canciones que han permanecido y fluctúan en popularidad.
# Clasificación de canciones nuevas o recurrentes
df_nuevas <- df_combinado %>%
mutate(
tipo_cancion = case_when(
origen == "billboard" & semanas_en_lista == 1 ~ "Nueva entrada",
origen == "billboard" & semanas_en_lista > 1 ~ "Recurrente",
origen == "apple" & abs(cambio_global) <= 2 ~ "Nueva entrada",
origen == "apple" & abs(cambio_global) > 2 ~ "Recurrente",
TRUE ~ "Desconocido"
)
) %>%
group_by(origen, tipo_cancion) %>%
summarise(canciones = n(), .groups = "drop")
# Gráfico comparativo
g_nuevas <- ggplot(df_nuevas, aes(x = origen, y = canciones, fill = tipo_cancion)) +
geom_col(position = "dodge") +
scale_fill_manual(values = c("Nueva entrada" = "#00BCD4", "Recurrente" = "#8BC34A", "Desconocido" = "gray")) +
labs(
title = "Canciones nuevas vs. recurrentes en Billboard y Apple Music",
x = "Plataforma",
y = "Número de canciones",
fill = "Tipo de canción"
) +
theme_economist() +
theme(
plot.title = element_text(face = "bold", size = 16, hjust = 0.5, margin = margin(b = 10)),
axis.title.x = element_text(margin = margin(t = 15)),
axis.title.y = element_text(margin = margin(r = 15)),
legend.position = "bottom"
)
print(g_nuevas)El gráfico muestra la distribución de canciones nuevas entradas frente a recurrentes en ambas plataformas, revelando patrones distintos en cada mercado.
En Apple Music Global, se observa un número significativo de canciones nuevas (representadas en azul), lo que sugiere que el algoritmo global favorece el descubrimiento y la rotación rápida de contenido. Esto es consistente con una estrategia de streaming enfocada en mantener fresco el catálogo y recompensar lanzamientos recientes.
En contraste, Billboard Hot 100 presenta una proporción mucho mayor de canciones recurrentes (en verde), lo que refleja un mercado más estable, donde las canciones tienden a permanecer semanas o meses en el ranking. Este comportamiento es típico del mercado estadounidense, donde el éxito comercial se mide por longevidad y no solo por impacto inicial.
Esta diferencia subraya que:
- En Apple Music, el éxito está más ligado a la novedad y la viralidad.
- En Billboard, el éxito se construye con el tiempo, mediante ventas, radio y streams acumulados.
Conclusión general
Este análisis comparativo entre el Billboard Hot 100 y el ranking global de Apple Music revela no solo dos lógicas distintas en la construcción del éxito musical, sino también la emergencia de nuevas tendencias estratégicas en la industria.
El algoritmo de Apple Music prioriza el contenido emergente y los fenómenos virales, generando un catálogo dinámico con alto volumen de lanzamientos nuevos. Este modelo representa un entorno digital enfocado en el descubrimiento instantáneo, donde el impulso inicial y la tracción en redes sociales pueden elevar un tema al éxito en apenas unos días.
Por otro lado, Billboard Hot 100 valora la permanencia, la estabilidad en el tiempo y la presencia transversal en múltiples canales (radiodifusión, compras digitales, plataformas de streaming). Ejemplos como “Lose Control” de Teddy Swims, con 105 semanas en lista, o “Birds of a Feather” de Billie Eilish, con 77 semanas, evidencian que el impacto artístico y la conexión cultural profunda se consolidan a largo plazo.
Además de las diferencias en los modelos de éxito musical, la industria enfrenta una migración creciente de usuarios desde Spotify hacia Apple Music. Esta tendencia se ha intensificado en 2025 debido a varios factores críticos que han afectado la imagen y percepción de Spotify.
Por un lado, Spotify ha experimentado problemas técnicos, la implementación de políticas controvertidas como restricciones para ciertos usuarios y una subida de precios que ha generado malestar entre sus suscriptores. Más importante aún, una ola de críticas y boicots liderados tanto por artistas como por usuarios se ha desencadenado por las inversiones del CEO de Spotify en tecnología militar, así como por la aparición de publicidad vinculada a agencias controvertidas.
En contraste, Apple Music ha facilitado la migración mediante herramientas que permiten transferir playlists y librerías completas de otros servicios, haciendo el cambio más sencillo y atractivo.
Este impulso migratorio está potenciando la expansión de Apple Music, especialmente al ofrecer audio en calidad lossless y una integración más sólida con el ecosistema Apple, aspectos valorados por quienes buscan calidad sonora y experiencia fluida. Como resultado, Apple Music está ganando terreno como plataforma preferida para el descubrimiento y consumo musical, aprovechando la desconfianza y el desencanto actuales hacia Spotify.
Por otra parte, en cuanto a las nuevas tendencias musicales:
Lanzamientos múltiples por álbum: Taylor Swift ha posicionado 11–12 canciones simultáneamente de “The Life of a Showgirl”, aprovechando algoritmos que premian la variedad dentro de una discografía.
Globalización del K-pop: artistas como TWICE, BLACKPINK y KATSEYE dominan en Apple Music pero tienen menor presencia en Billboard, lo que evidencia un poder cultural creciente desde Asia hacia mercados globales.
En este contexto, cabe destacar que la industria ha visto una migración creciente de usuarios desde Spotify hacia Apple Music. Esta tendencia se ha intensificado en 2025 debido a varios factores críticos que han afectado la imagen y percepción de Spotify. Por un lado, Spotify ha experimentado problemas técnicos, la implementación de políticas controvertidas como restricciones para ciertos usuarios y una subida de precios que ha generado malestar entre sus suscriptores. Más importante aún, una ola de críticas y boicots liderados tanto por artistas como por usuarios se ha desencadenado por las inversiones del CEO de Spotify en tecnología militar, así como por la aparición de publicidad vinculada a agencias controvertidas.
En contraste, Apple Music ha facilitado la migración mediante herramientas que permiten transferir playlists y librerías completas de otros servicios, haciendo el cambio más sencillo y atractivo. Este impulso migratorio está potenciando la expansión de Apple Music, especialmente al ofrecer audio en calidad lossless y una integración más sólida con el ecosistema Apple, aspectos valorados por quienes buscan calidad sonora y experiencia fluida.
Como resultado, Apple Music está ganando terreno como plataforma preferida para el descubrimiento y consumo musical, aprovechando la desconfianza y el desencanto actuales hacia Spotify.
En conjunto, estos hallazgos muestran que el éxito musical moderno ya no depende de un solo modelo, sino de una combinación estratégica entre lo local y lo global, lo efímero y lo duradero, lo artístico y lo algorítmico. Esta complejidad es esencial para que sellos discográficos, artistas y plataformas diseñen campañas que maximicen tanto el impacto inmediato como la longevidad artística en un mercado cada vez más fragmentado pero interconectado.
Webgrafía
Moncanig. (2025). Tema 3: Análisis del turismo internacional. Recuperado de https://moncanig.quarto.pub/dne2526/Tema3.html
Billboard. (2025). Billboard Hot 100™: The week’s most popular current songs. Recuperado de https://www.billboard.com/charts/hot-100/
Kworb. (2025). Apple Music Top Songs Data. Recuperado de https://kworb.net/apple_songs/
Genius. (2025). Genius - Music lyrics, news, and annotations. Recuperado de https://genius.com/
Apple Support. (2025). Transfer a copy of your music playlists to Apple Music. Recuperado de https://support.apple.com/en-us/118249
Music Business Worldwide. (2025, septiembre 16). Apple expands tool allowing users to transfer playlists from Spotify and other services. Recuperado de https://www.musicbusinessworldwide.com/apple-expands-tool-allowing-users-to-transfer-playlists-from-spotify-and-other-services-to-us-uk-and-more/
ABC News Australia. (2025, septiembre 12). Spotify boycott stems from CEO’s ties to military AI and ICE recruitment ads. Recuperado de https://www.abc.net.au/news/2025-09-12/spotify-boycott-daniel-ek-ai-music-military-tech-fenn-wilson/105765846
Forbes. (2025, noviembre 8). Why the Spotify boycott is about more than music. Recuperado de https://www.forbes.com/sites/janicegassam/2025/11/08/why-the-spotify-boycott-is-about-more-than-music/
Goover.ai. (2025). SEO public report May 2025. Recuperado de https://seo.goover.ai/report/202505/go-public-report-en-a30d9469-567d-44f3-a528-f1971ade9dee-0-0.html